package main

import (
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/tjfoc/gmsm/sm2"
	"math/big"
	"net/http"
)

//================================================================================
type TSM2Sign struct {
	Src    string `json:"src" form:"src" binding:"required"`
	Format string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64, plain 或者为空
}

// 用自己的私钥签名
func r_sm2_sign(c *gin.Context) {
	input := &TSM2Sign{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.Format) == 0 {
		input.Format = "plain"
	}

	var data []byte

	switch input.Format {
	case "hex":
		data, err = hex.DecodeString(input.Src)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.Src)
		break
	case "plain":
		data = []byte(input.Src)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.Format)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	r, s, err := sm2.Sm2Sign(gSm2PrivKey, data, nil, nil)
	if err != nil {
		Return_ok_result(c, "1000", "签名出错："+err.Error(), nil)
		return
	}

	var buf []byte
	buf = append(buf, r.Bytes()...)
	buf = append(buf, s.Bytes()...)

	v := &ReturnValue{
		Code:    "0000",
		Message: "",
		Format:  "base64",
	}
	v.Data = base64.StdEncoding.EncodeToString(buf)
	c.JSON(http.StatusOK, v)
}

//================================================================================
type TSM2Verify struct {
	SrcData    string `json:"src" form:"src" binding:"required"`
	SrcFormat  string `json:"fmt,omitempty" form:"fmt,omitempty" binding:"required"` // 可能的值：hex, base64, plain 或者为空
	SignBase64 string `json:"sign" form:"sign" binding:"required"`
}

// 用汇元的公钥检查汇元的签名
func r_sm2_verify(c *gin.Context) {
	sm2_verify_common(c, gHySm2PubKey)
}

// 用自己的公钥检查自己的签名
func r_sm2_self_verify(c *gin.Context) {
	sm2_verify_common(c, gHySm2PubKey)
}

func sm2_verify_common(c *gin.Context, pubkey *sm2.PublicKey) {
	input := &TSM2Verify{}
	err := c.ShouldBind(input)
	if err != nil {
		Return_params_error_result(c, err)
		return
	}

	if len(input.SrcFormat) == 0 {
		input.SrcFormat = "plain"
	}

	var data []byte

	switch input.SrcFormat {
	case "hex":
		data, err = hex.DecodeString(input.SrcData)
		break
	case "base64":
		data, err = base64.StdEncoding.DecodeString(input.SrcData)
		break
	case "plain":
		data = []byte(input.SrcData)
		break
	default:
		err = fmt.Errorf("未知的数据格式: %v", input.SrcFormat)
	}

	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	sign, err := base64.StdEncoding.DecodeString(input.SignBase64)
	if err != nil {
		Return_ok_result(c, "1000", err.Error(), nil)
		return
	}

	r := new(big.Int).SetBytes(sign[:32])
	s := new(big.Int).SetBytes(sign[32:])

	bVerified := sm2.Sm2Verify(pubkey, data, nil, r, s)

	Return_sign_verification_result(c, bVerified)
}
